package com.litbw.user;

import java.util.List;

import com.litbw.event.Contest;
import com.litbw.event.Contest.Entry;
/**
 * 
 * @author Derrick Mink
 *
 */
public class User {

	private static final int CONTESTS_ALLOWED = 3;
	private UserRole my_role = UserRole.UNASSIGNED;
	private Contest my_contest;
	private Draft[] drafts = new Draft[3];

	private String first;
	private String last;
	private String email;
	private String phone;
	private String address;
	private String city;
	private String state;
	private String zip;

	private String password;

	private int num_drafts;

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("user[name='");
		sb.append(last);
		sb.append(", ");
		sb.append(first);
		sb.append("', email='");
		sb.append(email);
		sb.append("', phone=");
		sb.append(phone);
		sb.append(", address='");
		sb.append(address);
		sb.append("', city='");
		sb.append(city);
		sb.append("', state='");
		sb.append(state);
		sb.append("', zip='");
		sb.append(zip);
		sb.append("', username='");
		sb.append(email);
		sb.append("', password='");
		sb.append(password);
		sb.append("']");

		return sb.toString();
	}

	/**
	 * The password policy is: At least 8 characters Contains at least one digit
	 * Contains at least one lower alpha char and one upper alpha char Contains
	 * at least one char within a set of special char (@#%$^ etc.) Not
	 * containing blank, tab etc.
	 * 
	 * @param userName
	 *            a valid email address
	 * @param password
	 *            a valid password
	 * @throws InvalidDataException
	 */
	public User(String userName, String password) throws InvalidDataException {
		my_role = UserRole.UNASSIGNED;
		userName = userName.toLowerCase();
		if (DataValidator.isValidEmail(userName)) {
			email = userName;
		} else {
			throw new InvalidDataException("invalid email address: " + userName
					+ " not accepted");
		}

		if (DataValidator.isValidPassword(password)) {
			this.password = password;
		} else if (password == null) {
			// do nothing
		} else {
			throw new InvalidDataException(
					"invalid password: nust be 8c long, 1 digit, one lower, one upper, "
							+ "one special, and no spaces");
		}
	}

	public void changePassword(final String change) throws InvalidDataException {
		if (DataValidator.isValidPassword(change)) {
			password = change;
		} else {
			throw new InvalidDataException("password could not be changed");
		}
	}

	public String getPassword() {
		return password;
	}

	public String getUsername() {
		return email;
	}

	public void setRole(UserRole role) {
		my_role = role;
	}

	public void setAddress(String input) throws InvalidDataException {
		boolean accepted = DataValidator.isValidAddress(input);
		if (input != null && accepted) {
			address = input;
		} else {
			throw new InvalidDataException("Invalid Address");
		}
	}

	public void setName(String first, String last) throws InvalidDataException {
		first = DataValidator.formatName(first);
		last = DataValidator.formatName(last);
		boolean accepted = DataValidator.isValidFirst(first);
		if (accepted) {
			this.first = first;
		} else {
			throw new InvalidDataException(first + " is not a valid name");
		}

		accepted = DataValidator.isValidFirst(last);
		if (accepted) {
			this.last = last;
		} else {
			throw new InvalidDataException(first + " is not a valid name");
		}
	}

	public void setPhone(String input) throws InvalidDataException {
		boolean accepted = DataValidator.isValidPhone(input);
		if (accepted) {
			phone = input;
		} else {
			throw new InvalidDataException(input
					+ "is not a valid Phone Number");
		}
	}

	public void setCity(String input) throws InvalidDataException {

		boolean accepted = DataValidator.isValidCity(input);
		if (accepted) {
			city = input;
		} else {
			throw new InvalidDataException(input + "is not a valid City");
		}
	}

	public void setState(String input) throws InvalidDataException {
		boolean accepted = DataValidator.isValidState(input);
		if (accepted) {
			state = input;
		} else {
			throw new InvalidDataException(input + "is not a valid State");
		}
	}

	public void setZip(String input) throws InvalidDataException {
		boolean accepted = DataValidator.isValidZip(input);
		if (accepted) {
			zip = input;
		} else {
			throw new InvalidDataException(input + "is not a valid zip code");
		}
	}

	public UserRole getRole() {
		return my_role;
	}

	public String getName() {
		return last + ", " + first;
	}

	public String getPhone() {
		return phone;
	}

	public String getAddress() {
		return address;
	}

	public String getCity() {
		return city;
	}

	public String getState() {
		return state;
	}

	public String getZip() {
		return zip;
	}

	public String getEmail() {
		return email;
	}

	// /////////////////////////////////////////////////
	// //////////////JUDGE//ONLY////////////////////////
	// /////////////////////////////////////////////////
	/**
	 * Allows a Judge to be assigned to a contest
	 */
	public boolean assignContest(Contest the_contest) {
		if (my_role != UserRole.JUDGE || the_contest.getJudges().contains(this))
			return false;
		else
			the_contest.addJudge(this);
		my_contest = the_contest;
		return true;
	}

	public List<Entry> reviewEntries() {
		return my_contest.getEntries();
	}

	// /////////////////////////////////////////////////
	// /////////////CONTESTANT ONLY/////////////////////
	// /////////////////////////////////////////////////

	/**
	 * This method attaches a new draft to this user. If a user already has the
	 * maximum number of drafts an exception is thrown.
	 * 
	 * @param newDraft
	 * @throws OverTheLimitException
	 */
	public void addDraft(Draft newDraft) throws OverTheLimitException {
		if (my_role == UserRole.CONTESTANT && drafts.length <= CONTESTS_ALLOWED) {
			drafts[num_drafts++] = newDraft;
		} else {
			throw new OverTheLimitException(drafts.length);
		}
	}

	public boolean hasDraft() {
		return drafts.length >= 1;
	}
}
